package com.baoyouqun.API.IM;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baoyouqun.API.IM.entity.FriendStatus;
import com.baoyouqun.base.BusinessException;
import com.baoyouqun.entity.User;
import com.baoyouqun.entity.WechatPushRecord;
import com.baoyouqun.service.UserService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;

/**
 * 腾讯IM服务实现类（对接腾讯IM开放接口）
 */
@Slf4j
@Service
public class TencentImServiceImpl implements TencentImService {

    /**
     * 腾讯IM接口通用基础URL
     */
    private static final String IM_BASE_URL = "https://console.tim.qq.com/v4/";
    // 批量好友校验接口地址（替换为实际接口地址）
    private static final String FRIEND_CHECK_URL = "https://xxxxxx/v4/sns/friend_check";
    // 新增接口URL常量
    private static final String FRIEND_ADD_URL = IM_BASE_URL + "sns/friend_add";
    private static final String FRIEND_DELETE_URL = IM_BASE_URL + "sns/friend_delete";
    private static final String USER_STATE_URL = IM_BASE_URL + "openim/querystate";

    // 随机数生成器（避免高并发下的重复问题）
    private static final Random RANDOM = new Random();
    // 好友关系枚举常量
    private static final String CHECK_TYPE_BOTH = "CheckResult_Type_Both"; // 双向校验
    private static final String RELATION_BOTH_WAY = "CheckResult_Type_BothWay";
    private static final String RELATION_A_WITH_B = "CheckResult_Type_AWithB";
    private static final String RELATION_B_WITH_A = "CheckResult_Type_BWithA";
    private static final String RELATION_NO_RELATION = "CheckResult_Type_NoRelation";


    // 依赖注入HTTP请求工具（此处以OkHttp为例，实际项目可能使用RestTemplate等）
    @Resource
    private ImConfig imConfig;
    @Resource
    private TLSSigAPIv2 tlsSigAPI;
    @Resource
    private UserService userService;


    /**
     * 初始化IM用户（导入用户到腾讯IM）
     */
    @Override
    public JSONObject initImUser(String userId, String nick, String faceUrl) {
        try {
            // 1. 生成管理员UserSig
            String adminSig = tlsSigAPI.genUserSig(imConfig.getAdminUserId(), 86400);

            // 2. 构建请求URL
            String url = IM_BASE_URL + "im_open_login_svc/account_import" +
                    "?sdkappid=" + imConfig.getSdkAppId() +
                    "&identifier=" + imConfig.getAdminUserId() +
                    "&usersig=" + adminSig +
                    "&random=" + UUID.randomUUID().hashCode() +
                    "&contenttype=json";

            // 3. 构建请求体
            JSONObject requestBody = new JSONObject();
            JSONArray userList = new JSONArray();
            JSONObject user = new JSONObject();
            user.put("Identifier", userId);
            user.put("Nick", nick != null ? nick : "");
            user.put("FaceUrl", faceUrl != null ? faceUrl : "");
            userList.add(user);
            requestBody.put("UserList", userList);

            // 4. 发送请求
            String response = HttpUtil.post(url, requestBody.toString());
            return JSONObject.parseObject(response);
        } catch (Exception e) {
            throw new RuntimeException("初始化IM用户失败", e);
        }
    }

    /**
     * 发送系统消息（单聊）
     */
    @Override
    public JSONObject sendSystemMessage(String fromUserId, String toUserId, String content) {
        if (StringUtils.isBlank(fromUserId)) {
            throw new BusinessException("400", "发送者ID不能为空");
        }
        if (StringUtils.isBlank(toUserId)) {
            throw new BusinessException("400", "接收者ID不能为空");
        }
        if (StringUtils.isBlank(content)) {
            throw new BusinessException("400", "消息内容不能为空");
        }

        try {
            // 1. 生成发送者UserSig
            String senderSig = tlsSigAPI.genUserSig(fromUserId, 86400);

            // 2. 构建请求URL
            String url = IM_BASE_URL + "openim/sendmsg" +
                    "?sdkappid=" + imConfig.getSdkAppId() +
                    "&identifier=" + fromUserId +
                    "&usersig=" + senderSig +
                    "&random=" + UUID.randomUUID().hashCode() +
                    "&contenttype=json";

            // 3. 构建消息体
            JSONObject requestBody = new JSONObject();
            requestBody.put("SyncOtherMachine", 1); // 同步到其他终端
            requestBody.put("From_Account", fromUserId);
            requestBody.put("To_Account", toUserId);

            // 支持多种消息类型（文本、图片等），这里以文本为例
            JSONObject msgBody = new JSONObject();
            msgBody.put("MsgType", "TIMTextElem");
            JSONObject textContent = new JSONObject();
            textContent.put("Text", content);
            msgBody.put("MsgContent", textContent);

            JSONArray msgList = new JSONArray();
            msgList.add(msgBody);
            requestBody.put("MsgBody", msgList);
            requestBody.put("MsgRandom", UUID.randomUUID().hashCode());
            requestBody.put("MsgTime", System.currentTimeMillis() / 1000);

            // 4. 发送请求并返回结果
            String response = HttpUtil.post(url, requestBody.toString());
            JSONObject result = JSONObject.parseObject(response);

            // 记录发送日志
            if (result.getIntValue("ErrorCode") == 0) {
                log.info("系统消息发送成功，从[{}]到[{}]，内容：{}", fromUserId, toUserId, content);
            } else {
                log.error("系统消息发送失败，错误信息：{}", result.getString("ErrorInfo"));
            }

            return result;
        } catch (Exception e) {
            log.error("发送系统消息异常", e);
            throw new RuntimeException("发送系统消息失败", e);
        }
    }

    /**
     * 验证回调签名（确保请求来自腾讯IM）
     */
    @Override
    public boolean verifyCallbackSignature(String signature, String nonce, String timestamp, String body) {
        try {
            // 腾讯IM回调签名规则：signature = base64(sha1(sdkappid + body + nonce + timestamp + secretkey))
            String raw = imConfig.getSdkAppId() + body + nonce + timestamp + imConfig.getSecretKey();
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            byte[] digest = md.digest(raw.getBytes(StandardCharsets.UTF_8));
            String calculated = Base64.getEncoder().encodeToString(digest);
            return calculated.equals(signature);
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 实现：查询在线用户ID列表（对接腾讯IM接口）
     */
    @Override
    public Set<String> getOnlineUserIds() {
        try {
            // 1. 生成管理员UserSig
            String adminSig = tlsSigAPI.genUserSig(imConfig.getAdminUserId(), 86400);

            // 2. 构建腾讯IM“查询用户在线状态”接口URL
            String url = IM_BASE_URL + "openim/querystate" +
                    "?sdkappid=" + imConfig.getSdkAppId() +
                    "&identifier=" + imConfig.getAdminUserId() +
                    "&usersig=" + adminSig +
                    "&random=" + UUID.randomUUID().hashCode() +
                    "&contenttype=json";

            // 3. 构建请求体（注：腾讯IM此接口需指定用户列表，若需全量在线用户需先获取所有用户ID，此处简化为示例）
            // 实际场景：若用户量小，可传所有公开用户ID；若用户量大，需结合IM的“在线状态回调”缓存在线用户
            JSONObject requestBody = new JSONObject();
            JSONArray toAccount = new JSONArray();
            // 临时逻辑：先查询所有公开用户ID（实际需优化，避免全量查询）
            List<String> publicUserIds = userService.list(new LambdaQueryWrapper<User>()
                            .select(User::getId)
                            .eq(User::getIsPublic, true)
                            .eq(User::getDisEnable, false)
                            .eq(User::getLogout, false)
                    ).stream()
                    .map(User::getId)
                    .collect(Collectors.toList());
            toAccount.addAll(publicUserIds);
            requestBody.put("To_Account", toAccount);

            // 4. 发送请求并解析响应
            String response = HttpUtil.post(url, requestBody.toString());
            JSONObject result = JSONObject.parseObject(response);
            if (result.getIntValue("ErrorCode") != 0) {
                throw new RuntimeException("查询在线状态失败：" + result.getString("ErrorInfo"));
            }

            // 5. 提取在线用户ID（State=Online表示在线）
            JSONArray userStateList = result.getJSONArray("UserStateList");
            return userStateList.stream()
                    .map(JSONObject.class::cast)
                    .filter(state -> "Online".equals(state.getString("State")))
                    .map(state -> state.getString("To_Account"))
                    .collect(Collectors.toSet());
        } catch (Exception e) {
            // 异常时返回空集合（避免影响列表展示）
            return Set.of();
        }
    }

    @Override
    public List<FriendStatus> batchCheckFriends(String fromAccount, String userSig, List<String> toAccounts) {
        // 1. 参数校验（保持不变）
        if (StringUtils.isBlank(fromAccount)) {
            throw new BusinessException("400", "发起方账号不能为空");
        }
        if (StringUtils.isBlank(userSig)) {
            throw new BusinessException("400", "用户签名不能为空");
        }
        if (CollUtil.isEmpty(toAccounts)) {
            return Collections.emptyList();
        }

        // 2. 构建请求参数（保持不变）
        JSONObject requestBody = new JSONObject();
        requestBody.put("From_Account", fromAccount);
        requestBody.put("To_Account", toAccounts);
        requestBody.put("CheckType", CHECK_TYPE_BOTH);

        // 3. 构建完整请求URL
        String requestUrl = String.format("%s?sdkappid=%s&identifier=%s&usersig=%s&random=%d&contenttype=json",
                FRIEND_CHECK_URL,
                imConfig.getSdkAppId(),
                fromAccount,
                userSig,
                new Random().nextInt(1000000)
        );

        // 4. 使用Hutool的HttpUtil发送POST请求
        String responseJson;
        try (HttpResponse response = HttpRequest.post(requestUrl)
                .body(requestBody.toJSONString())
                .contentType("application/json; charset=utf-8")
                .execute()) {

            if (!response.isOk()) { // 判断HTTP状态码是否为200-299
                throw new BusinessException("500", "调用IM接口失败，HTTP状态码：" + response.getStatus());
            }
            responseJson = response.body();
        } catch (Exception e) {
            throw new BusinessException("500", "调用IM接口发生异常：" + e.getMessage());
        }

        // 5. 解析接口响应（后续逻辑保持不变）
        JSONObject responseObj = JSONObject.parseObject(responseJson);
        String actionStatus = responseObj.getString("ActionStatus");
        int errorCode = responseObj.getIntValue("ErrorCode");
        if (!"OK".equals(actionStatus) || errorCode != 0) {
            throw new BusinessException("500", "IM接口返回错误：" + responseObj.getString("ErrorInfo") + "（错误码：" + errorCode + "）");
        }

        List<FriendStatus> result = new ArrayList<>();
        JSONArray checkResults = responseObj.getJSONArray("CheckResult");
        if (checkResults == null || checkResults.isEmpty()) {
            return fillMissingAccounts(toAccounts, new ArrayList<>(), result);
        }

        List<String> returnedAccounts = new ArrayList<>();
        for (Object obj : checkResults) {
            if (!(obj instanceof JSONObject checkResult)) {
                continue;
            }
            String toAccount = checkResult.getString("To_Account");
            if (StringUtils.isBlank(toAccount) || !toAccounts.contains(toAccount)) {
                continue;
            }

            returnedAccounts.add(toAccount);
            String relation = checkResult.getString("Relation");
            int blackFlag = checkResult.getIntValue("BlackFlag", 0);

            FriendStatus status = new FriendStatus();
            status.setFriendUserId(toAccount);
            status.setFriend(RELATION_BOTH_WAY.equals(relation) || RELATION_A_WITH_B.equals(relation));
            status.setRemark(getRelationDescription(relation));

            result.add(status);
        }

        return fillMissingAccounts(toAccounts, returnedAccounts, result);
    }

    @Override
    public void sendBatchMessage(String senderImId, List<String> receiverUserIds, WechatPushRecord messageVO) {
        // 参数校验（原有逻辑保留）
        if (CollUtil.isEmpty(receiverUserIds)) {
            log.warn("批量发送消息失败：接收者列表为空");
            return;
        }
        if (messageVO == null || StringUtils.isBlank(messageVO.getContent())) {
            throw new BusinessException("400", "消息内容不能为空");
        }
        if (StringUtils.isBlank(senderImId)) {
            throw new BusinessException("400", "发送者ID不能为空");
        }

        try {
            // 1. 生成发送者UserSig（系统消息建议使用管理员账号）
            String senderSig = tlsSigAPI.genUserSig(senderImId, 86400); // 24小时有效期

            // 2. 构建基础请求URL（不含接收者参数，循环中动态添加）
            String baseUrl = IM_BASE_URL + "openim/sendmsg" +
                    "?sdkappid=" + imConfig.getSdkAppId() +
                    "&identifier=" + senderImId +
                    "&usersig=" + senderSig +
                    "&random=" + generateValidRandom() + // 这里也替换为合法的随机数（URL参数的random也需符合32位无符号）
                    "&contenttype=json";

            // 3. 构建通用消息体（不含接收者和MsgRandom，循环中动态设置）
            JSONObject baseRequestBody = new JSONObject();
            baseRequestBody.put("SyncOtherMachine", 1); // 同步到接收者的其他终端
            baseRequestBody.put("From_Account", senderImId);
            baseRequestBody.put("MsgTime", System.currentTimeMillis() / 1000); // 秒级时间戳（正确格式）

            // 构建消息内容（文本类型，原有逻辑保留）
            JSONObject msgBody = new JSONObject();
            msgBody.put("MsgType", "TIMTextElem");
            JSONObject textContent = new JSONObject();
            textContent.put("Text", messageVO.getContent()); // 从WechatPushVO获取内容
            msgBody.put("MsgContent", textContent);
            JSONArray msgList = new JSONArray();
            msgList.add(msgBody);
            baseRequestBody.put("MsgBody", msgList);

            // 4. 循环向每个接收者发送消息
            for (String receiverId : receiverUserIds) {
                // 深拷贝基础消息体，避免循环中参数污染
                JSONObject requestBody = baseRequestBody.clone();
                requestBody.put("To_Account", receiverId); // 设置当前接收者
                requestBody.put("MsgRandom", generateValidMsgRandom()); // 关键修改：生成合法的MsgRandom

                // 打印日志，方便调试（可选）
                log.debug("发送IM消息：URL={}，请求体={}", baseUrl, requestBody);

                // 发送请求
                String response = HttpUtil.post(baseUrl, requestBody.toString());
                JSONObject result = JSONObject.parseObject(response);

                // 处理发送结果
                if (result.getIntValue("ErrorCode") != 0) {
                    log.error("向用户[{}]发送批量消息失败：错误码={}，错误信息={}",
                            receiverId, result.getIntValue("ErrorCode"), result.getString("ErrorInfo"));
                    // 可根据业务需求选择是否抛出异常（此处选择继续发送其他用户）
                } else {
                    log.info("向用户[{}]发送批量消息成功", receiverId);
                }
            }
        } catch (Exception e) {
            log.error("批量发送消息异常", e);
            throw new BusinessException("500", "批量发送消息失败：" + e.getMessage());
        }
    }

    /**
     * 生成符合腾讯云IM要求的 MsgRandom（32位无符号整数，范围0~4294967295）
     */
    private long generateValidMsgRandom() {
        // ThreadLocalRandom 线程安全，生成 [0, 4294967295] 之间的随机数
        return ThreadLocalRandom.current().nextLong(0, 4294967296L);
    }

    /**
     * 生成URL参数中合法的 random（同MsgRandom格式要求）
     */
    private long generateValidRandom() {
        return generateValidMsgRandom();
    }

    /**
     * 补充未在IM接口返回结果中的用户（默认标记为非好友、非黑名单）
     */
    private List<FriendStatus> fillMissingAccounts(List<String> allAccounts, List<String> returnedAccounts, List<FriendStatus> result) {
        Set<String> returnedSet = new HashSet<>(returnedAccounts);
        List<String> missingAccounts = allAccounts.stream()
                .filter(account -> !returnedSet.contains(account))
                .collect(Collectors.toList());

        for (String missingAccount : missingAccounts) {
            FriendStatus status = new FriendStatus();
            status.setFriendUserId(missingAccount);
            status.setFriend(false);
            status.setRemark("未查询到关系（默认非好友）");
            result.add(status);
        }

        return result;
    }

    /**
     * 转换关系类型为可读性描述
     */
    private String getRelationDescription(String relation) {
        return switch (relation) {
            case RELATION_BOTH_WAY -> "双向好友（双方互加好友）";
            case RELATION_A_WITH_B -> "当前用户已添加对方为好友，对方未添加当前用户";
            case RELATION_B_WITH_A -> "对方已添加当前用户为好友，当前用户未添加对方";
            case RELATION_NO_RELATION -> "非好友关系（双方均未添加）";
            default -> "未知关系类型：" + relation;
        };
    }

    /**
     * 实现添加好友功能（对接腾讯IM好友添加接口）
     */
    @Override
    public JSONObject addFriend(String fromUserId, String toUserId, String remark) {
        try {
            // 1. 生成发起方的UserSig
            String userSig = tlsSigAPI.genUserSig(fromUserId, 86400);

            // 2. 构建请求URL
            String url = FRIEND_ADD_URL +
                    "?sdkappid=" + imConfig.getSdkAppId() +
                    "&identifier=" + fromUserId +
                    "&usersig=" + userSig +
                    "&random=" + UUID.randomUUID().hashCode() +
                    "&contenttype=json";

            // 3. 构建请求体
            JSONObject requestBody = new JSONObject();
            requestBody.put("From_Account", fromUserId);

            JSONArray toAccountList = new JSONArray();
            JSONObject friendItem = new JSONObject();
            friendItem.put("To_Account", toUserId);
            friendItem.put("Remark", StringUtils.isNotBlank(remark) ? remark : "");
            // 可选：设置添加来源（如"搜索添加"）
            friendItem.put("AddSource", "API");
            toAccountList.add(friendItem);

            requestBody.put("AddFriendItem", toAccountList);

            // 4. 发送请求并返回结果
            String response = HttpUtil.post(url, requestBody.toString());
            return JSONObject.parseObject(response);
        } catch (Exception e) {
            throw new RuntimeException("添加好友失败", e);
        }
    }

    /**
     * 实现删除好友功能（对接腾讯IM好友删除接口）
     */
    @Override
    public JSONObject deleteFriend(String fromUserId, String toUserId) {
        try {
            // 1. 生成发起方的UserSig
            String userSig = tlsSigAPI.genUserSig(fromUserId, 86400);

            // 2. 构建请求URL
            String url = FRIEND_DELETE_URL +
                    "?sdkappid=" + imConfig.getSdkAppId() +
                    "&identifier=" + fromUserId +
                    "&usersig=" + userSig +
                    "&random=" + UUID.randomUUID().hashCode() +
                    "&contenttype=json";

            // 3. 构建请求体
            JSONObject requestBody = new JSONObject();
            requestBody.put("From_Account", fromUserId);

            JSONArray toAccountList = new JSONArray();
            toAccountList.add(toUserId);
            requestBody.put("To_Account", toAccountList);

            // 4. 发送请求并返回结果
            String response = HttpUtil.post(url, requestBody.toString());
            return JSONObject.parseObject(response);
        } catch (Exception e) {
            throw new RuntimeException("删除好友失败", e);
        }
    }

    /**
     * 实现查询指定用户在线状态功能
     */
    @Override
    public Map<String, String> getOnlineStatus(List<String> userIds) {
        if (CollUtil.isEmpty(userIds)) {
            return Collections.emptyMap();
        }

        try {
            // 1. 生成管理员UserSig
            String adminSig = tlsSigAPI.genUserSig(imConfig.getAdminUserId(), 86400);

            // 2. 构建请求URL
            String url = USER_STATE_URL +
                    "?sdkappid=" + imConfig.getSdkAppId() +
                    "&identifier=" + imConfig.getAdminUserId() +
                    "&usersig=" + adminSig +
                    "&random=" + UUID.randomUUID().hashCode() +
                    "&contenttype=json";

            // 3. 构建请求体（传入指定用户列表）
            JSONObject requestBody = new JSONObject();
            JSONArray toAccount = new JSONArray();
            toAccount.addAll(userIds);
            requestBody.put("To_Account", toAccount);

            // 4. 发送请求并解析响应
            String response = HttpUtil.post(url, requestBody.toString());
            JSONObject result = JSONObject.parseObject(response);

            if (result.getIntValue("ErrorCode") != 0) {
                throw new RuntimeException("查询在线状态失败：" + result.getString("ErrorInfo"));
            }

            // 5. 提取用户状态（键：用户ID，值：状态）
            Map<String, String> statusMap = new HashMap<>(userIds.size());
            // 关键修复：判断userStateList是否为null，若为null则初始化为空数组
            JSONArray userStateList = result.getJSONArray("UserStateList");
            if (userStateList == null) {
                userStateList = new JSONArray();
            }

            for (Object obj : userStateList) {
                JSONObject state = (JSONObject) obj;
                String userId = state.getString("To_Account");
                String status = state.getString("State"); // Online/Offline等
                statusMap.put(userId, status);
            }

            // 补充未返回的用户（默认离线）
            userIds.forEach(userId -> statusMap.putIfAbsent(userId, "Offline"));
            return statusMap;
        } catch (Exception e) {
            throw new RuntimeException("查询用户在线状态失败", e);
        }
    }

    /**
     * 同步用户头像到腾讯IM（使用Tag_Profile_IM_Image标签）
     *
     * @param userId     腾讯IM的UserId（需与本地用户ID一致）
     * @param headImgUrl 新头像公网URL
     * @return 同步是否成功
     */
    @Override
    public void syncUserHeadImg(String userId, String headImgUrl) {
        if (StringUtils.isBlank(userId)) {
            log.error("400", "用户ID不能为空");
        }
        if (StringUtils.isBlank(headImgUrl)) {
            log.error("400", "头像URL不能为空");
        }

        try {
            // 1. 生成管理员签名（修改资料建议使用管理员权限）
            String adminSig = tlsSigAPI.genUserSig(imConfig.getAdminUserId(), 86400);

            // 2. 构建请求URL（腾讯IM修改资料接口）
            String url = IM_BASE_URL + "profile/modify_profile" +
                    "?sdkappid=" + imConfig.getSdkAppId() +
                    "&identifier=" + imConfig.getAdminUserId() +
                    "&usersig=" + adminSig +
                    "&random=" + UUID.randomUUID().hashCode() +
                    "&contenttype=json";

            // 3. 构建请求体（指定头像标签Tag_Profile_IM_Image）
            JSONObject requestBody = new JSONObject();
            requestBody.put("From_Account", userId); // 要修改的用户ID

            JSONArray profileItems = new JSONArray();
            JSONObject imgItem = new JSONObject();
            imgItem.put("Tag", "Tag_Profile_IM_Image"); // 腾讯IM头像标准标签
            imgItem.put("Value", headImgUrl); // 头像URL
            profileItems.add(imgItem);

            requestBody.put("ProfileItem", profileItems);

            // 4. 发送请求
            String response = HttpUtil.post(url, requestBody.toString());
            JSONObject result = JSONObject.parseObject(response);

            // 5. 校验接口返回结果（ErrorCode=0表示成功）
            if (result.getIntValue("ErrorCode") != 0) {
                log.error("500",
                        "同步头像失败：" + result.getString("ErrorInfo") + "（错误码：" + result.getIntValue("ErrorCode") + "）");
            }
        } catch (Exception e) {
            log.error("500", "同步头像发生异常：" + e.getMessage());
        }
    }


}